/**
 * Copyright (c) 2011-2016, James Zhan 詹波 (jfinal@126.com).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.candy.db.generator.core;


import com.candy.db.generator.config.GlobalConfig;
import com.candy.db.generator.utils.BeanToMap;
import com.candy.db.generator.utils.FreeMarkerKit;
import com.candy.db.generator.utils.LogKit;
import com.candy.db.generator.utils.StrKit;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * Base model 生成器
 */
public class BaseModelGenerator {
    protected String pkDefineTemplate =
            "\t@Id(name=\"%s\")%n"+
                    "\tprivate  %s %s;%n%n";
    protected String attrDefineTemplate =
            "\t@Column(name=\"%s\")%n"+
                    "\tprivate  %s %s;%n%n";
	protected String packageTemplate =
		"package %s;%n%n";
	protected String importTemplate =
            "import java.util.Date;%n" +
                    "import cn.at.mo.framework.dao.annotation.Column;%n" +
                    "import cn.at.mo.framework.dao.annotation.Id;%n" +
                    "import cn.at.mo.framework.dao.annotation.Table;%n";
	protected String classDefineTemplate =
		"/**%n" +
		" */%n" +
        "@Table(name=\"%s\")%n"+
		"public class %s  {%n%n";
	protected String setterTemplate =
			"\tpublic void %s(%s %s) {%n" +
				"\t\tthis.%s = %s;%n" +
			"\t}%n%n";
	protected String getterTemplate =
			"\tpublic %s %s() {%n" +
				"\t\treturn %s;%n" +
			"\t}%n%n";
	
	protected String baseModelPackageName;
	protected String baseModelOutputDir;
	
	protected JavaKeyword javaKeyword = new JavaKeyword();
	
	public BaseModelGenerator(String baseModelPackageName, String baseModelOutputDir) {
		if (StrKit.isBlank(baseModelPackageName))
			throw new IllegalArgumentException("baseModelPackageName can not be blank.");
		if (baseModelPackageName.contains("/") || baseModelPackageName.contains("\\"))
			throw new IllegalArgumentException("baseModelPackageName error : " + baseModelPackageName);
		if (StrKit.isBlank(baseModelOutputDir))
			throw new IllegalArgumentException("baseModelOutputDir can not be blank.");
		
		this.baseModelPackageName = baseModelPackageName;
		this.baseModelOutputDir = baseModelOutputDir;
	}
	
	public void generate(List<TableMeta> tableMetas) {
		System.out.println("Generate base model ...");
		for (TableMeta tableMeta : tableMetas)
			genBaseModelContent(tableMeta);
//		wirtToFile(tableMetas);
	}
	
	protected void genBaseModelContent(TableMeta tableMeta) {
        String modelDaoName = tableMeta.baseModelName;
        File file = new File(baseModelOutputDir+File.separator+modelDaoName+ GlobalConfig.exportFileSuffix);
        if(file.exists() && !GlobalConfig.overrideForce){
            LogKit.debug("file :" + file.getAbsolutePath() + " exist! Ignore  it ...");
            return;
        }
        if(!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        Map rootMap = BeanToMap.Bean2Map(tableMeta);
        rootMap.put("baseModelPackageName",baseModelPackageName);
        rootMap.put("author",GlobalConfig.classAuthor);

        FreeMarkerKit.make(rootMap, "base_model.ftl", file.getAbsolutePath());
	}

    private void genAttr(ColumnMeta columnMeta, StringBuilder ret) {
        if("PRI".equalsIgnoreCase(columnMeta.isPrimaryKey) || columnMeta.attrName.equalsIgnoreCase("id")){
            ret.append(String.format(pkDefineTemplate, columnMeta.name,columnMeta.javaType,columnMeta.attrName));
        }else{
            ret.append(String.format(attrDefineTemplate, columnMeta.name,columnMeta.javaType,columnMeta.attrName));
        }
    }

    protected void genPackage(StringBuilder ret) {
		ret.append(String.format(packageTemplate, baseModelPackageName));
	}
	
	protected void genImport(StringBuilder ret) {
		ret.append(String.format(importTemplate));
	}
	
	protected void genClassDefine(TableMeta tableMeta, StringBuilder ret) {
		//ret.append(String.format(classDefineTemplate, tableMeta.baseModelName, tableMeta.baseModelName));
		ret.append(String.format(classDefineTemplate, tableMeta.name, tableMeta.modelName));
	}
	
	protected void genSetMethodName(ColumnMeta columnMeta, StringBuilder ret) {
		String setterMethodName = "set" + StrKit.firstCharToUpperCase(columnMeta.attrName);
		// 如果 setter 参数名为 java 语言关键字，则添加下划线前缀 "_"
		String argName = javaKeyword.contains(columnMeta.attrName) ? "_" + columnMeta.attrName : columnMeta.attrName;
//		String setter = String.format(setterTemplate, setterMethodName, columnMeta.javaType, argName, columnMeta.name, argName);
		String setter = String.format(setterTemplate, setterMethodName, columnMeta.javaType, argName, columnMeta.attrName,argName);
		ret.append(setter);
	}
	
	protected void genGetMethodName(ColumnMeta columnMeta, StringBuilder ret) {
		String getterMethodName = "get" + StrKit.firstCharToUpperCase(columnMeta.attrName);
		String getter = String.format(getterTemplate, columnMeta.javaType, getterMethodName, columnMeta.attrName);
		ret.append(getter);
	}
	
	protected void wirtToFile(List<TableMeta> tableMetas) {
		try {
			for (TableMeta tableMeta : tableMetas)
				wirtToFile(tableMeta);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * base model 覆盖写入
	 */
	protected void wirtToFile(TableMeta tableMeta) throws IOException {
		File dir = new File(baseModelOutputDir);
		if (!dir.exists())
			dir.mkdirs();
		
		String target = baseModelOutputDir + File.separator + tableMeta.modelName + ".java";
		FileWriter fw = new FileWriter(target);
		try {
			fw.write(tableMeta.baseModelContent);
		}
		finally {
			fw.close();
		}
	}
}






